package pl.edu.mimuw.irs.rcp.persistence;

import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.part.FileEditorInput;

import pl.edu.mimuw.irs.core.model.design.resource.Resources;
import pl.edu.mimuw.irs.core.model.design.resource.Roles;
import pl.edu.mimuw.irs.rcp.util.Logger;
import pl.edu.mimuw.irs.rcp.util.MessageCode;

public class PersistenceManager {

	// *** Static properties

	public static final QualifiedName SESSION_RESOURCES = new QualifiedName("", "Resources");
	public static final QualifiedName SESSION_ROLES = new QualifiedName("", "Roles");

	public static final String RESOURCES_FILE = "resources.res";
	public static final String ROLES_FILE = "roles.rls";
	
	// *** Static attributes
	
	private static Map<IProject, PersistenceManager> map;
	public static Map<IProject, PersistenceManager> getMap() {
		if (map == null) map = new LinkedHashMap<IProject, PersistenceManager>();
		return map;
	}
	
	// *** Static methods
	
	public static PersistenceManager getInstance(IProject project, IProgressMonitor progress) throws CoreException {
		if (project == null) return null;
		PersistenceManager manager = getMap().get(project);
		if (manager == null) {
			manager = new PersistenceManager(project, progress);
			getMap().put(project, manager);
		}
		return manager;
	}
	
	public static PersistenceManager getInstance(IProject project) throws CoreException {
		return getInstance(project, null);
	}
	
	public static PersistenceManager getInstance(IEditorInput input, IProgressMonitor progress) throws CoreException {
		if (!(input instanceof FileEditorInput)) return null;
		FileEditorInput fileEditorInput = (FileEditorInput)input;
		IFile file = fileEditorInput.getFile();
		if (file == null) return null;
		IProject project = file.getProject();
		return getInstance(project, progress);		
	}
	
	public static PersistenceManager getInstance(IEditorInput input) throws CoreException {
		return getInstance(input, null);	
	}
	
	// *** Attributes

	private IProject project;
	public IProject getProject() {
		return project;
	}
	
	// *** Constructors

	private PersistenceManager(IProject project, IProgressMonitor progress) throws CoreException {
		this.project = project;
		project.open(progress);
	}
	
	// *** Methods
	
	public void close(IProgressMonitor progress) throws CoreException {
		project.close(progress);
	}
	
	public void close() throws CoreException {
		close(null);
	}
	
	public Roles getRoles() {
		if (getProject() == null) return null;
		/*
		 * We have project, now we have to get resources from session property
		 * or create it if we are first.
		 */
		Roles roles = null;
		try {
			roles = (Roles) getProject().getSessionProperty(SESSION_ROLES);
		} catch (CoreException e) {
			Logger.handle(MessageCode.ROLES_LOAD_DESERIALIZE_PROBLEM, e, SESSION_ROLES);
			return null;
		}
		if (roles == null) {
			IFile resourcesFile = project.getFile(ROLES_FILE);
			if (resourcesFile == null) return null;
			try {
				InputStream stream = resourcesFile.getContents();
				IPersistence<Roles> manager = PersistenceAdapter.getManager(Roles.class);
				roles = manager.loadFromStream(stream);
			} catch (CoreException e) {
				Logger.handle(MessageCode.ROLES_LOAD_DESERIALIZE_PROBLEM, e, resourcesFile.getName());
				return null;
			} catch (Exception e) {
				Logger.handle(MessageCode.ROLES_LOAD_DESERIALIZE_PROBLEM, e, resourcesFile.getName());
				return null;
			}
			
			try {
				project.setSessionProperty(SESSION_ROLES, roles);
			} catch (CoreException e) {
				Logger.handle(MessageCode.ROLES_SAVE_SERIALIZE_PROBLEM, e, SESSION_RESOURCES);
				return null;
			}
		}
		
		return roles;
	}
	
	public void clearRoles() {
		if (getProject() == null) return;
		try {
			project.setSessionProperty(SESSION_ROLES, null);
		} catch (CoreException e) {
			Logger.handle(MessageCode.ROLES_CLEAR_PROBLEM, e, SESSION_ROLES);
			return;
		}
	}
	
	public Resources getResources() {
		if (getProject() == null) return null;
		/*
		 * We have project, now we have to get resources from session property
		 * or create it if we are first.
		 */
		Resources resources = null;
		try {
			resources = (Resources) getProject().getSessionProperty(SESSION_RESOURCES);
		} catch (CoreException e) {
			Logger.handle(MessageCode.RESOURCES_LOAD_DESERIALIZE_PROBLEM, e, SESSION_RESOURCES);
			return null;
		}
		if (resources == null) {
			IFile resourcesFile = project.getFile(RESOURCES_FILE);
			if (resourcesFile == null) return null;
			try {
				InputStream stream = resourcesFile.getContents();
				IPersistence<Resources> manager = PersistenceAdapter.getManager(Resources.class);
				resources = manager.loadFromStream(stream);
			} catch (CoreException e) {
				Logger.handle(MessageCode.RESOURCES_LOAD_DESERIALIZE_PROBLEM, e, resourcesFile.getName());
				return null;
			} catch (Exception e) {
				Logger.handle(MessageCode.RESOURCES_LOAD_DESERIALIZE_PROBLEM, e, resourcesFile.getName());
				return null;
			}
			
			try {
				project.setSessionProperty(SESSION_RESOURCES, resources);
			} catch (CoreException e) {
				Logger.handle(MessageCode.RESOURCES_SAVE_SERIALIZE_PROBLEM, e, SESSION_RESOURCES);
				return null;
			}
		}
		
		return resources;
	}
	
	public void clearResources() {
		if (getProject() == null) return;
		try {
			project.setSessionProperty(SESSION_RESOURCES, null);
		} catch (CoreException e) {
			Logger.handle(MessageCode.RESOURCES_CLEAR_PROBLEM, e, SESSION_RESOURCES);
			return;
		}
	}
}
